import * as THREE from "../../../modules/three/three.module.js";
import {SprayAnimateDirEnum, WorldConfig} from "../lib/CommonConsts.js";
import SprayPerformer from "../lib/gadget/SprayPerformer.js";
import {interpolatePoints} from "../lib/util/StaticMethods.js";
import World3dEvent from "../scene/event/World3dEvent.js";

const sprayPerformer = new SprayPerformer(0.4)
// 和场景相机的 up 属性一致
sprayPerformer.up.set(0, 0, 1)

const canvasSize = 256
function createPaintingTexture(boxes, cssColorStr, material, ctx) {
  let context = ctx
  if (!context) {
    const canvas = document.createElement('canvas')
    canvas.width = canvasSize
    canvas.height = canvasSize
    context = canvas.getContext( '2d' )
    const texture = new THREE.CanvasTexture(canvas)
    // texture.encoding = THREE.LinearEncoding
    material.map = texture
  }
  // if (autoClear)
  // context.clearRect(0, 0, canvasSize, canvasSize)
  // context.beginPath()

  context.fillStyle = cssColorStr
  const s = canvasSize
  boxes.forEach(box => {
    const {min, max} = box
    const dx = max.x - min.x
    const dy = max.y - min.y
    context.rect(min.x * s, min.y * s, dx * s, dy * s)
    context.fill()
  })
  material.map.needsUpdate = true
  return context
}

// 对单个航线的喷涂动画，可能涉及多个工作区，不确定的喷涂路线
export class SprayPathAnimation {
  scene
  workAreaMeshes
  // 动画是否提前终止
  _canceled = false
  /**
   * @type {SprayPathAnimateItem[]}
   */
  animateItems = []
  /**
   * 航线喷涂的油漆颜色
   * @type {string}
   * @private
   */
  _areaColor
  _colorBaks = new Map()
  /**
   * @type {Map<number, CanvasRenderingContext2D>>}
   * @private
   */
  _mapCanvasCtx = new Map()
  /**
   * true 表示 动画的数据存在错误
   * @type {boolean}
   * @private
   */
  _invalid = false

  constructor(world3d, sprayPath) {
    this.scene = world3d.scene;
    this.store = world3d.store;
    const pathReader = world3d.pathReader;
    if (sprayPath) {
      const {w, h} = pathReader.sprayRect;
      this._initSprayPath(sprayPath, w, h);
    }
  }

  _initSprayPath(sprayPath, w, h) {
    sprayPath.interpolateCoords();
    const workAreaMeshes = this.store.areaMeshes.filter(it => sprayPath.workAreaIds.includes(it.vo.id));
    const workAreas = workAreaMeshes.map(it => it.vo);
    if (!workAreas.length) {
      console.error("工作区数据 和 AI的航线数据不匹配，无法播放动画");
      this._invalid = true;
      return;
    }
    this.animateItems = sprayPath.createAnimateItems(workAreas, w, h);
    this.workAreaMeshes = workAreaMeshes;
    workAreaMeshes.forEach(it => this._colorBaks.set(it.vo.id, '#' + it.material.color.getHexString()));

    const facing = sprayPath.facing;
    const {x, y, z} = facing;
    sprayPerformer.position.set(0, 0, 0);
    sprayPerformer.lookAt(x, y, z);
    this._areaColor = sprayPath.cssColorStr;
    sprayPerformer.setSprayColor(this._areaColor);
  }

  /**
   * 播放编辑路径的喷涂动画
   * @param {AddSprayPathPointPlugin} plugin
   */
  setPathByPlugin(plugin) {
    plugin.updateSprayPath();
    const sprayPath = plugin.sprayPath;
    if (!sprayPath) {
      console.error("编辑的航线数据没有，可能没有进行编辑 或者 编辑了航线，但是航线对应的工作区被删除了");
      this._invalid = true;
    } else {
      const {w, h} = sprayPath.editableRect;
      this._initSprayPath(sprayPath, w, h);
    }
  }

  /**
   * @param {SprayPathAnimateItem} animateItem
   * @private
   */
  _updateWorkAreaTexture(animateItem) {
    const workAreaMesh = this.workAreaMeshes.find(mesh => mesh.vo === animateItem.workArea)
    workAreaMesh.visible = true
    let context = this._mapCanvasCtx.get(animateItem.workArea.id)
    context = createPaintingTexture([animateItem.box], this._areaColor, workAreaMesh.material, context)
    this._mapCanvasCtx.set(animateItem.workArea.id, context)
  }

  _stopAni() {
    if (this._invalid) {
      return
    }
    this._mapCanvasCtx.clear()
    setTimeout(() => {
      this.workAreaMeshes.forEach(workAreaMesh => {
        workAreaMesh.visible = true
        workAreaMesh.material.map = null
        // workAreaMesh.material.color.setStyle(this._areaColor)
        const color = this._colorBaks.get(workAreaMesh.vo.id);
        if (color) {
          workAreaMesh.material.color.setStyle(color);
        }
      })
    }, 3000)
    sprayPerformer.removeFromParent()
  }

  updateAni() {
    if (this._invalid) {
      return
    }
    if (this.isCompleted()) {
      return
    }
    if (!sprayPerformer.parent) {
      this.scene.add(sprayPerformer)
      this.workAreaMeshes.forEach(workAreaMesh => {
        workAreaMesh.material.color.setStyle('#fff')
        workAreaMesh.visible = false
      })
    }
    const obj = this.animateItems.shift()
    if (obj.workArea) {
      this._updateWorkAreaTexture(obj)
      sprayPerformer.toggleLine(this.animateItems.length % 2 === 0)
    } else {
      sprayPerformer.toggleLine(false)
    }
    // if (obj.spraying) {
    //   console.log('AI called spraying');
    // }
    sprayPerformer.position.copy(obj.droneWorldPos)
    sprayPerformer.animateDronePaddle()
    if (!this.animateItems.length) { // 动画完成
      this._stopAni()
    }
  }

  cancelAni() {
    this._canceled = true
    this._stopAni()
  }

  isCompleted() {
    return this._invalid || this._canceled || !this.animateItems.length
  }
}
